package com.taldh.reflect.types;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * date: 2020/5/25
 *
 * @author 袁小黑
 * @version 1.0.0
 */

public class LearnWhatIsType<K extends Number, T> {

    private HashMap<String, Object> map;
    private HashSet<String> set;
    private List<String> list;
    private Class<? extends Number> clazz;
    private Sample<?> sample;

    static class Sample<T> {
        public void test() {
            System.out.println("test");
        }
    }

    private static void printParameterizedType() {
        // filed 只能拿到public的filed， declaredFields 能拿到private的filed.
        //ParameterizedType：参数化类型   ———— 参数化类型即我们通常所说的泛型类型
        Field[] fields = LearnWhatIsType.class.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("FieldName: " + field.getName() + "\tinstanceof ParameteriezdType \t" + field.getGenericType().getTypeName());
            System.out.println("FieldName:  " + field.getName() + " instanceof ParameterizedType is : " +
                    (field.getGenericType() instanceof ParameterizedType));
            if (field.getGenericType() instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
                System.out.println("((ParameterizedType) field.getGenericType()).getRawType() = " + ((ParameterizedType) field.getGenericType()).getRawType());
                System.out.println("((ParameterizedType) field.getGenericType()).getOwnerType() = " + ((ParameterizedType) field.getGenericType()).getOwnerType());
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    System.out.println("FiledName " + field.getName() + " 第 " + i + "个参数为: " + actualTypeArguments[i].getTypeName());
                    System.out.println("actualTypeArguments[i].equals(String.class) = " + actualTypeArguments[i].equals(String.class));
                    System.out.println("actualTypeArguments[i].getClass().isAssignableFrom(Number.class) = " + Number.class.isAssignableFrom(actualTypeArguments[i].getClass()));
                }
            }
        }
    }

    //K有指定了上边界Number
    K key;
    //T没有指定上边界，其默认上边界为Object
    T value;

    private static void printTypeVariable() {
        //范型信息在编译时会被转换为一个特定的类型, 而TypeVariable就是用来反映在JVM编译该泛型前的信息。
        // (通俗的来说，TypeVariable就是我们常用的T，K这种泛型变量)
        Type[] types = LearnWhatIsType.class.getTypeParameters();
        for (Type type : types){
            TypeVariable t = (TypeVariable) type;
            int index = t.getBounds().length - 1;
            //输出上边界
            System.out.println("--getBounds()-- " + t.getBounds()[index]);
            //输出名称
            System.out.println("--getName()--" + t.getName());
            System.out.println("t.getName().equals(\"K\") = " + t.getName().equals("K"));
            //输出所在的类的类型
            System.out.println("--getGenericDeclaration()--" + t.getGenericDeclaration());
        }
    }

    //泛型数组类型
    private T[] valueTs;
    private List<String>[] listLs;

    //不是泛型数组类型
    private List<String> singleList;
    private T singleValue;

    private static void printGenericArrayType() {
        Field[] fields = LearnWhatIsType.class.getDeclaredFields();
        for (Field field: fields){
            field.setAccessible(true);
            //输出当前变量是否为GenericArrayType类型
            System.out.println("Field: "
                    + field.getName()
                    + "; instanceof GenericArrayType"
                    + ": "
                    + (field.getGenericType() instanceof GenericArrayType));
            if (field.getGenericType() instanceof GenericArrayType){
                //如果是GenericArrayType，则输出当前泛型类型
                Type genericComponentType = ((GenericArrayType) field.getGenericType()).getGenericComponentType();
                System.out.println("Field: "
                        + field.getName()
                        + "; getGenericComponentType()"
                        + ": "
                        + genericComponentType);
                if (genericComponentType instanceof ParameterizedType) {
                    System.out.println("((ParameterizedType) genericComponentType).getActualTypeArguments()[0] = " + ((ParameterizedType) genericComponentType).getActualTypeArguments()[0]);
                    System.out.println(((ParameterizedType) genericComponentType).getActualTypeArguments()[0].getTypeName().equals(String.class.getName()));
                }
            }
        }
    }

    private static void printWildcardType() {
        //获取TestWildcardType类的所有方法(本例中即 testWildcardType 方法)
        Method[] methods = LearnWhatIsType.class.getDeclaredMethods();
        for (Method method: methods){
            System.out.println("method.getName() = " + method.getName());
            //获取方法的所有参数类型
            Type[] types = method.getGenericParameterTypes();
            for (Type paramsType: types){
                System.out.println("type: " + paramsType.toString());
                //如果不是参数化类型则直接continue，执行下一个循环条件
                if (!(paramsType instanceof ParameterizedType)){
                    continue;
                }
                //将当前类型强转为参数化类型并获取其实际参数类型(即含有通配符的泛型类型)
                Type type = ((ParameterizedType) paramsType).getActualTypeArguments()[0];
                //输出其是否为通配符类型
                System.out.println("type instanceof WildcardType : " +
                        ( type instanceof WildcardType));
                if (type instanceof WildcardType){
                    int lowIndex = ((WildcardType) type).getLowerBounds().length - 1;
                    int upperIndex = ((WildcardType) type).getUpperBounds().length - 1;
                    //输出上边界与下边界
                    System.out.println("getLowerBounds(): "
                            +
                            (lowIndex >= 0 ? ((WildcardType) type).getLowerBounds()[lowIndex] : "String ")
                            + "; getUpperBounds(): "
                            +
                            (upperIndex >=0 ? ((WildcardType) type).getUpperBounds()[upperIndex]:"Object"));
                }
            }
        }
    }

    public void testWildcardType(List<? extends OutputStream> numberList,
                                 List<? super InputStream> upperList,  List<Integer> list, InputStream inputStream){}

    public static void main(String[] args) {
//        printParameterizedType();
//        printTypeVariable();
//        printGenericArrayType();
        //printWildcardType();
        System.out.println(HashMap.class.getGenericSuperclass() instanceof ParameterizedType);
    }


}
